#pragma once

#include "noncopyable.h"
#include "Timestamp.h"

#include <memory>
#include <functional>

class EventLoop;

/**
 * Channel意为通道，封装了sockfd和其关心的事件。
 * 也绑定了Poller返回的就绪事件
 */
class Channel : noncopyable
{
public:
    typedef std::function<void()> EventCallback;
    typedef std::function<void(Timestamp)> ReadEventCallback;

    Channel(EventLoop *loop, int fd);
    ~Channel();

    // fd得到Poller通知以后，处理事件的
    void handleEvent(Timestamp receiveTime);

    // 设置传入对应事件的回调函数
    // cb在赋值完成后就没用了，故采用std::move将cb转化为右值，以实现移动语义
    void setReadCallback(ReadEventCallback cb) { readCallback_ = std::move(cb); }
    void setWriteCallbcak(EventCallback cb) { writeCallback_ = std::move(cb); }
    void setCloseCallback(EventCallback cb) { closeCallback_ = std::move(cb); }
    void setErrorCallback(EventCallback cb) { errorCallback_ = std::move(cb); }

    void setrEventCallback(EventCallback cb) { eventCallback_ = std::move(cb); }

    // 防止当channel被手动remove后，channel仍然在执行回调操作
    void tie(const std::shared_ptr<void> &obj);

    int fd() const { return fd_; }
    int events() const { return events_; }

    // 传入就绪事件。就绪时间时Poller监听到的
    void set_revents(int revt) { revents_ = revt; }
    int revents() {return revents_;}    //为了调试

    // 使能接口，更改关心的事件events_，并在Poller中更新监听事件
    void enableReading()
    {
        events_ |= kReadEvent;
        update();
    }
    void disableReading()
    {
        events_ &= ~kReadEvent;
        update();
    }
    void enableWriting()
    {
        events_ |= kWriteEvent;
        update();
    }
    void disableWriting()
    {
        events_ &= ~kWriteEvent;
        update();
    }
    void disableAll()
    {
        events_ = kNoneEvent;
        update();
    }

    // 获取fd当前的事件状态
    bool isNoneEvent() const { return events_ == kNoneEvent; }
    bool isReading() const { return events_ & kReadEvent; }
    bool isWriting() const { return events_ & kWriteEvent; }

    int index() { return index_; }
    void set_index(int idx) { index_ = idx; }

    EventLoop *ownerLoop() { return loop_; }
    void remove();

private:
    // 当改变Channel所存储的fd的关心事件后，在update赋值更新Poller中对该fd的监听事件
    void update();
    void handleEventWithGuard(Timestamp receiveTime);

private:
    // 对事件的关心状态
    static const int kNoneEvent;
    static const int kReadEvent;
    static const int kWriteEvent;

    EventLoop *loop_;
    const int fd_;
    int events_;
    int revents_; // Poller返回的已经就绪的事件
    int index_;   // 表示channel是否添加到Poller中，详见EPollPoller.cc的const

    // 定义一个弱指针，指向TcpConnection对象，弱指针不会使底层计数器+1
    std::weak_ptr<void> tie_;
    bool tied_;

    // 对应事件的回调函数
    ReadEventCallback readCallback_;
    EventCallback writeCallback_;
    EventCallback closeCallback_;
    EventCallback errorCallback_;
    EventCallback eventCallback_;
};